#pragma once
#include "coroutine/coroutine.h"
#include "noncopyable.h"
#include <functional>
#include <memory>
#include "future.hpp"
namespace TinyRPC{
/**
 * task 既可以是一个协程， 也可以是一个普通的任务函数
 * 甚至可以传一个异步函数进行,
 */
class Task{
public:
    
    using TaskFunc = std::function<void()>;
    template<typename T>
    using TaskFuncWithReturn = std::function<T()>;

    Task(const TaskFunc& taskFunc, bool isCoroutine, std::string name="corou");
    Task(CoroutinePtr coroutine);

    // 建立一个异步协程任务
    template<typename T>
    static Task AsyncTask(const TaskFuncWithReturn<T>& taskFunc, Future<T>& future);

    // 无论是function还是coroutine都可以通过统一的api run() 来调用
    void run() const;

    static Task EmptyTask(){
        return Task();
    }

    bool isCoroutine() const{
        return m_isCoroutine;
    }

    bool isEmptyTask(){
        return m_taskFunc == nullptr  && m_coroutine == nullptr;
    }

private:
    Task();
    template<typename T>
    static void AsyncFunc(const TaskFuncWithReturn<T>& taskFunc, Future<T>& future);

private:
    bool m_isCoroutine;
    TaskFunc m_taskFunc;
    std::shared_ptr<Coroutine> m_coroutine;
};

using TaskPtr = std::shared_ptr<Task>;


template<typename T>
Task Task::AsyncTask(const TaskFuncWithReturn<T>& taskFunc, Future<T>& future){
    return Task(std::bind(&Task::AsyncFunc<T>, taskFunc, std::ref(future)), true);
}

template<typename T>
void Task::AsyncFunc(const TaskFuncWithReturn<T>& taskFunc, Future<T>& future){
    future.set(taskFunc());
}

}
